/*
 * Systemprogrammierung
 * Multiplayer-Quiz
 *
 * Gemeinsam verwendete Module
 *
 * sockets.c: Implementierung der Socket-Funktionen zum Senden und Empfangen
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "rfc.h"
#include "sockets.h"
//#include "../user.h"
//#include "../clientthread.h"
#include "util.h"

//Clientsocket erstellen, um sich mit der Adresse zu verbinden
int CreateClientSocket(char* ip, char* port)
{
	struct addrinfo *addr_info, *p;
	int ret, sock;
	ret = getaddrinfo(ip, port, NULL, &addr_info);
	if (ret)
	{
		printf("getaddrinfo: %s\n", gai_strerror(ret));
		exit(-1);
	}

	p= addr_info;

	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock==-1)
	{
		perror("socket");
		return -1;
	}

	if (sonnect(sock, p->ai_addr, p->ai_addrlen) == 0)
	{
		freeaddrinfo(addr_info);
		return sock;
	}
	freeaddrinfo(addr_info);
	return 0;
}

//TODO Listener Socket erzeugen (

//TODO Client Verbindun akzeptieren

//TODO RFC nachricht empfangen

//TODO RFC Nachricht erstellen, die mit SendRFCMsg versendet wird

//TODO RFC Nachricht versenden

// Erstellt ein NET_MESSAGE struct aus einem übergebenen Packet-Type und den zu sendenden Nutzdaten
struct NET_MESSAGE server_CreateMessage(uint8_t iType, char *sData) {
	struct NET_HEADER oHeader;
	struct NET_MESSAGE oMessage;

	infoPrint("\nErzeuge Message: %i - %s", iType, sData);

	// Header
	oHeader.type = iType;
	oHeader.size = strlen(sData);

	infoPrint("\nLength: %i", oHeader.size);

	// Data
	oMessage.header = oHeader;
	strcpy(oMessage.data, sData);

	return oMessage;
}

// Sendet eine NET_MESSAGE über ein angegebenes iSocket
// Returns SEND_ERROR bei Fehler und die Anzahl der gesendeten Bytes bei Erfolg
int server_SendServerMessage(int iSocket, struct NET_MESSAGE oMessage) {
	char sMessage[65535];

	sMessage[0] = (uint8_t)oMessage.header.type;
	sMessage[1] = (uint8_t)(oMessage.header.size / 256);
	sMessage[2] = (uint8_t)oMessage.header.size;
	strcpy(sMessage + 3, oMessage.data);

	infoPrint("\nGesendet: %s", sMessage);


	if (write(iSocket, sMessage, ((int)oMessage.header.size) + 3) == ((int)oMessage.header.size) + 3) {
		return ((int)oMessage.header.size) + 3;
	}
	else {
		errorPrint("\nERROR while sending to client");
		return SEND_ERROR;
	}
}

int server_CheckMessageLength(char *sMessage) {
	return 0;
}

void sockets_ServerListeningLoop() {
	int iTemp;
	char sTemp[512];

	int iPort;
	int iListeningSocket, iNewClientSocket;
	static char sBuffer[512];
	socklen_t iNewClientLength;
	struct sockaddr_in oServerAddress, oSocket_ClientAddress;

	iPort = atoi(TCP_DEFAULT_PORT);
	iListeningSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (iListeningSocket < 0) {
    	errorPrint("\nERROR opening listener-socket");
    }
    else {
        bzero((char *) &oServerAddress, sizeof(oServerAddress));
        oServerAddress.sin_family = AF_INET;
        oServerAddress.sin_addr.s_addr = INADDR_ANY;
        oServerAddress.sin_port = htons(iPort);

        if (bind(iListeningSocket, (struct sockaddr *) &oServerAddress, sizeof(oServerAddress)) < 0) {
        	errorPrint("\nERROR binding listener-socket");
        }
        else {
        	///////////////////////////////////
        	// ##### Listener Schleife ##### //
        	///////////////////////////////////
        	while (1) {

        		infoPrint("\nStarting to listen ...");
                listen(iListeningSocket, 5);

                // Neue Verbindung annehmen
                iNewClientLength = sizeof(oSocket_ClientAddress);
                iNewClientSocket = accept(iListeningSocket, (struct sockaddr *) &oSocket_ClientAddress, &iNewClientLength);
                if (iNewClientSocket < 0) {
                	errorPrint("\nERROR on accepting new connection");
                }
                else {
                	// Auf Daten warten
                	bzero(sBuffer, 512);
            		iTemp = read(iNewClientSocket, sBuffer, sizeof(sBuffer));
            		if (iTemp > 0) {
            			sBuffer[iTemp] = '\0';

            			infoPrint("\nBytes empfangen: %i", iTemp);
            			infoPrint("\nCasting Buffer[0] to int: %i", (int)sBuffer[0]);
            			// Ueberpruefen auf Login-Request (1. Byte (int)1)
            			if ((int)sBuffer[0] == 1) {
            				// Gueltiges Request
            				strcpy(sTemp, sBuffer + 3);
            				infoPrint("\nAusgelesener Name: %s", sTemp);

            				// Prüfe Spielphase

            				// Prüfe Nutzeranzahl
            				if (user_GetUserCount() < 6) {
								// Prüfe Mindestlänge
								if (strlen(sTemp) > 3) {
									// Prüfe Maximallänge
									if (strlen(sTemp) < 16) {
										// Prüfe Einzigartigkeit des Namens
										if (user_UsernameAlreadyTaken(sTemp) == 0) {
											iTemp = user_AddNewUser(sTemp, iNewClientSocket);
											if (iTemp > -1) {
												// ID zu String konvertieren
												sprintf(sBuffer,"%d",iTemp);
												infoPrint("BlaBlub");
												infoPrint("%s",sBuffer);
												// Antwort senden
												server_SendServerMessage(iNewClientSocket, server_CreateMessage(TYPE_IS_LOGIN_RESPONSE_OK, sBuffer));

												clientt_CreateClientThread(iTemp);
											}
											else {
												server_SendServerMessage(iNewClientSocket, server_CreateMessage(TYPE_IS_ERROR, "Fehler: Konnte user nicht anlegen"));
											}

											server_SendServerMessage(iNewClientSocket, server_CreateMessage(TYPE_IS_ERROR, "Fehler: Name zu lang"));
										}
										else {
											server_SendServerMessage(iNewClientSocket, server_CreateMessage(TYPE_IS_ERROR, "Fehler: Name bereits in Verwendung"));
										}
									}
									else {
										server_SendServerMessage(iNewClientSocket, server_CreateMessage(TYPE_IS_ERROR, "Fehler: Name zu lang"));
									}
								}
								else {
									server_SendServerMessage(iNewClientSocket, server_CreateMessage(TYPE_IS_ERROR, "Fehler: Name zu kurz"));
								}
            				}
            				else {
            					server_SendServerMessage(iNewClientSocket, server_CreateMessage(TYPE_IS_ERROR, "Fehler: Alle Plaetze belegt"));
            				}
            			}

            			//close(oNewClientSocket);

            		}
            		else {
            			errorPrint("\nERROR failed reading data");
            		}

                }

        	}

        }
    }

	return;

}
